/**
 * Class for popup balloons.
 *
 * @author Andrey Anisimov <hercules@inbox.ru>
 */

import core.ui.Window;
import core.util.Timer;

// TODO: inherit from Popup or Infotip
class Balloon extends Window {
	
	/**
	 * Creates new balloon.
	 *
	 * @param owner (Window) owner control
	 * @param text (string) text in balloon
	 * @param position (int) [optional] balloon position (Balloon.TOP by default)
	 * @param timeout (int) [optional] time in seconds to display a balloon (10 by default).
	 */
	this.Balloon = function(owner, text, position, timeout) {
		super();
		
		this.setStyle('overflow', 'visible');
		this.setStyle('z-index', Balloon.ZINDEX);

		this.timer = new Timer((timeout || 0) * 1000);
        this.timer.addTimerListener(this);

		this.tail = this.createTail();
		this.setPosition(position || Balloon.TOP);
		this.setOwner(owner);
		this.setText(text);
	}
	
	/**
	 * Sets the balloon's owner control.
	 *
	 * @param owner (Window) new owner.
	 */
	this.setOwner = function(owner) {
		this.owner = owner;
	}
	
	/**
	 * Returns the balloon's owner control.
	 *
	 * @return Window
	 */
	this.getOwner = function() {
		return this.owner;
	}
	
	/**
	 * Sets balloon position.
	 *
	 * @param pos (int) new position.
	 */
	this.setPosition = function(pos) {
		// Styling prefixes
		var names = {};
		names[Balloon.LEFT] = 'left';
		names[Balloon.TOP] = 'top';
		names[Balloon.RIGHT] = 'right';
		names[Balloon.BOTTOM] = 'bottom';
		
		this.removeStyleName(this.getStyleName() + '-' + names[this.position & Balloon.MASK_POSTITON]);
		this.tail.removeStyleName(this.tail.getStyleName() + '-' + names[this.position & Balloon.MASK_POSTITON]);
		
		this.position = pos;
		
		this.addStyleName(this.getStyleName() + '-' + names[this.position & Balloon.MASK_POSTITON]);
		this.tail.addStyleName(this.tail.getStyleName() + '-' + names[this.position & Balloon.MASK_POSTITON]);
	}
	
	/**
	 * Returns balloon position.
	 *
	 * @return int
	 */
	this.getPosition = function() {
		return this.position;
	}

	/**
	 * Sets the time to display a balloon.
	 *
	 * Note: you can specify zero timeout as a parameter.
	 * This will make a balloon always visible until user clicks on it,
	 * or until the problem described in balloon's text is resolved.
	 * 
	 * @param d (int) time in seconds
	 */
	this.setTimeout = function(d) {
		this.timer.setInterval(d * 1000);
	}
	
	/**
	 * Returns current balloon duration in seconds.
	 *
	 * @return int
	 */
	this.getTimeout = function() {
		return this.timer.getInterval() / 1000;
	}
	
	/**
	 * Sets whether the balloon is visible.
	 *
	 * Note: the balloon position is automatically adjustable,
	 * so you only need to call balloon.show() and it will be
	 * adjusted to be fully displayed on the screen.
	 * 
	 * @param show (bool) true to show the balloon, false to hide.
	 */
	this.setVisible = function(show) {
		if (show) {
			this.attachGlobalEvent('mousemove');
			this.adjustPosition();
			if (0 != this.timer.getInterval()) {
				this.timer.start();
			}
		} else {
			this.timer.stop();
			this.detachGlobalEvent('mousemove');
		}
		this.tail.setVisible(show);
		super.setVisible(show);
	}
	
	/**
	 * Returns this balloon's tail component.
	 *
	 * @return Window
	 */
	this.getTail = function() {
		return this.tail;
	}
	
	/**
	 * Sets whether the balloon is enabled.
	 *
	 * @param e (bool) true to enable, false to disable the balloon.
	 */
	this.setEnabled = function(e) {
		this.tail.setEnabled(e);
		super.setEnabled(e);
	}
	
	/**
	 * Closes balloon tip and deletes its content.
	 */
	this.close = function() {
		this.timer.stop();
		this.tail.close();
		delete this.tail;
		super.close();
	}
	
	/**
	 * @protected
	 * Creates and returns tail for balloon.
	 * @return Window
	 */
	this.createTail = function() {
		var tail = new Window();
		tail.setStyleName(this.getStyleName() + 'Tail');
		tail.setStyle('z-index', Balloon.ZINDEX);
		return tail;
	}

	/**
	 * @protected
	 * Corrects position in correspondence with screen edges.
	 */
	this.correctPosition = function() {

		var balloonX = 0;
		var balloonY = 0;

		if (this.position & Balloon.LEFT) {

			var tailX = this.owner.getAbsX() - this.tail.getWidth();
			var tailY = this.owner.getAbsY() + (this.owner.getHeight() - this.tail.getHeight())/2;

			balloonX = tailX - this.getWidth();
			balloonY = tailY - (this.getHeight() - this.tail.getHeight())/2;
				
		} else if (this.position & Balloon.RIGHT) {
			
			var tailX = this.owner.getAbsX() + this.owner.getWidth();
			var tailY = this.owner.getAbsY() + (this.owner.getHeight() - this.tail.getHeight())/2;

			balloonX = tailX + this.tail.getWidth();
			balloonY = tailY - (this.getHeight() - this.tail.getHeight())/2;
			
		} else if (this.position & Balloon.TOP) {
			
			var tailX = this.owner.getAbsX() + (this.owner.getWidth() - this.tail.getWidth())/2;
			var tailY = this.owner.getAbsY() - this.tail.getHeight();
				
			balloonX = tailX - (this.getWidth() - this.tail.getWidth())/2;
			balloonY = tailY - this.getHeight();
			
		} else if (this.position & Balloon.BOTTOM) {
			
			var tailX = this.owner.getAbsX() + (this.owner.getWidth() - this.tail.getWidth())/2;
			var tailY = this.owner.getAbsY() + this.owner.getHeight();
				
			balloonX = tailX - (this.getWidth() - this.tail.getWidth())/2;
			balloonY = tailY + this.tail.getHeight();
			
		}

		var screenLeft = document.body.scrollLeft;
		var screenRight = document.body.clientWidth + document.body.scrollLeft;
		var screenTop = document.body.scrollTop;
		var screenBottom = document.body.clientHeight + document.body.scrollTop;

		// check left and right
		if (balloonX < screenLeft) {
			this.setPosition(Balloon.RIGHT | (this.position & Balloon.FLOATING));
		} else if (balloonX + this.getWidth() > screenRight) {
			this.setPosition(Balloon.LEFT | (this.position & Balloon.FLOATING));
		}

		// check top and bottom
		if (balloonY < screenTop) {
			this.setPosition(Balloon.BOTTOM | (this.position & Balloon.FLOATING));
		} else if (balloonY + this.getHeight() > screenBottom) {
			this.setPosition(Balloon.TOP | (this.position & Balloon.FLOATING));
		}
	}
	
	/**
	 * @protected
	 * Adjustes balloon tip position on the screen, so it must be completely visible.
	 */
	this.adjustPosition = function() {

		if (this.position & Balloon.FLOATING) {
			this.correctPosition();
		}
		
		if (this.position & Balloon.LEFT) {
			
			this.tail.move(this.owner.getAbsX() - this.tail.getWidth(),
				this.owner.getAbsY() + (this.owner.getHeight() - this.tail.getHeight())/2);
				
			this.move(this.tail.getX() - this.getWidth(),
				this.tail.getY() - (this.getHeight() - this.tail.getHeight())/2);
				
		} else if (this.position & Balloon.RIGHT) {
			
			this.tail.move(this.owner.getAbsX() + this.owner.getWidth(),
				this.owner.getAbsY() + (this.owner.getHeight() - this.tail.getHeight())/2);
				
			this.move(this.tail.getX() + this.tail.getWidth(),
				this.tail.getY() - (this.getHeight() - this.tail.getHeight())/2);
			
		} else if (this.position & Balloon.TOP) {
			
			this.tail.move(this.owner.getAbsX() + (this.owner.getWidth() - this.tail.getWidth())/2,
				this.owner.getAbsY() - this.tail.getHeight());
				
			this.move(this.tail.getX() - (this.getWidth() - this.tail.getWidth())/2,
				this.tail.getY() - this.getHeight());
			
		} else if (this.position & Balloon.BOTTOM) {
			
			this.tail.move(this.owner.getAbsX() + (this.owner.getWidth() - this.tail.getWidth())/2,
				this.owner.getAbsY() + this.owner.getHeight());
				
			this.move(this.tail.getX() - (this.getWidth() - this.tail.getWidth())/2,
				this.tail.getY() + this.tail.getHeight());
			
		}
	}
	
	this.onmousedown = function(event, target) {
		if ((target instanceof Window) && ((target == this) || target.isChildOf(this))) {
			if (this.isVisible()) {
				this.hide();
			}
		}
	}
	
	this.onmousemove = function(event) {
		// Adjust balloon position every time owner control is moved.
		var info = arguments.callee;
		if ((this.owner.getAbsX() !== info.x) || (this.owner.getAbsY() !== info.y)) {
			info.x = this.owner.getX();
			info.y = this.owner.getY();
			this.adjustPosition();
		}
	}
	
	this.onTimer = function() {
		if (this.isVisible()) {
			this.hide();
		}
	}
}

core.ui.Balloon.LEFT = 0x01;
core.ui.Balloon.TOP = 0x02;
core.ui.Balloon.RIGHT = 0x04
core.ui.Balloon.BOTTOM = 0x08;
core.ui.Balloon.FLOATING = 0x10;

core.ui.Balloon.MASK_POSTITON = 0xF;

core.ui.Balloon.ZINDEX = 10000;
